Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add read-only calendar from url #126862

Closed
wants to merge 4 commits into from

Conversation

zeehio
Copy link
Contributor

@zeehio zeehio commented Sep 26, 2024

Proposed change

Allow to provide a URL pointing to an ics file when creating a local calendar. If the URL is given, the calendar becomes read-only and shows events from the ics provided by the URL. The integration will refresh the URL once a day by default, although the update interval is customizable.

This is useful for users who live in towns who publish local holidays or garbage collection information in ics files, if they want to have such information in home assistant.

Type of change

  • Dependency upgrade
  • Bugfix (non-breaking change which fixes an issue)
  • New integration (thank you!)
  • New feature (which adds functionality to an existing integration)
  • Deprecation (breaking change to happen in the future)
  • Breaking change (fix/feature causing existing functionality to break)
  • Code quality improvements to existing code or addition of tests

Additional information

  • This PR fixes or closes issue: fixes #
  • This PR is related to issue:
  • Link to documentation pull request:

Checklist

  • The code change is tested and works locally.
  • Local tests pass. Your PR cannot be merged unless tests pass
  • There is no commented out code in this PR.
  • I have followed the development checklist
  • I have followed the perfect PR recommendations
  • The code has been formatted using Ruff (ruff format homeassistant tests)
  • Tests have been added to verify that the new code works.

If user exposed functionality or configuration variables are added/changed:

If the code communicates with devices, web services, or third-party tools:

  • The manifest file has all fields filled out correctly.
    Updated and included derived files by running: python3 -m script.hassfest.
  • New or updated dependencies have been added to requirements_all.txt.
    Updated by running python3 -m script.gen_requirements_all.
  • For the updated dependencies - a link to the changelog, or at minimum a diff between library versions is added to the PR description.

To help with the load of incoming pull requests:

@home-assistant
Copy link

Hey there @allenporter, mind taking a look at this pull request as it has been labeled with an integration (local_calendar) you are listed as a code owner for? Thanks!

Code owner commands

Code owners of local_calendar can trigger bot actions by commenting:

  • @home-assistant close Closes the pull request.
  • @home-assistant rename Awesome new title Renames the pull request.
  • @home-assistant reopen Reopen the pull request.
  • @home-assistant unassign local_calendar Removes the current integration label and assignees on the pull request, add the integration domain after the command.
  • @home-assistant add-label needs-more-information Add a label (needs-more-information, problem in dependency, problem in custom component) to the pull request.
  • @home-assistant remove-label needs-more-information Remove a label (needs-more-information, problem in dependency, problem in custom component) on the pull request.

@zeehio
Copy link
Contributor Author

zeehio commented Sep 26, 2024

Screenshot_20240926-224635

@zeehio zeehio force-pushed the feature/local-calendar-url branch from 91f436a to 3fe1b6b Compare September 26, 2024 21:53
@Misiu
Copy link
Contributor

Misiu commented Sep 28, 2024

Not sure if we can add an expandable panel to the config flow, but it would be nice to have ICS URL and time interval in a separate section that is hidden by default.

Copy link
Contributor

@allenporter allenporter left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I like to target near 100% test coverage for this integration.

vol.Optional(CONF_CALENDAR_URL): TextSelector(
TextSelectorConfig(type=TextSelectorType.URL)
),
vol.Optional(CONF_SYNC_INTERVAL): DurationSelector(
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This needs to be removed from the config flow. The design standards for how to do updates are here https://developers.home-assistant.io/docs/integration_fetching_data/ -- This is something generic that applies to any entity and not something we want to add to the integration specific configuration flow.

The way we'll want to handle this is:

  • Pick a reasonable default for how often to refresh this (not too often)
  • Users can add their own automation and a schedule using an action call to homeassistant.update_entity to refresh

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I will follow those instructions. Thank you. I have a lot to learn about coding for home assistant integrations.

Since each remote calendar entity has its own URL, I first thought I should go for Separate polling for each individual entity, and use the async_update() method for polling the data.

However I believe the async_update() method is currently called when the calendar entity needs to update the next event attribute, and I do not think we need to fetch the data that frequently. Considering this, having one coordinator class for each entity seems to make more sense. Would you agree? Suggestions are welcome.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Great thanks. Very happy to have your contribution, and while there is a learning curve it is quite rewarding to contribute to home assistant so really happy to help here. You have a great start already and reviewers are happy to point out best practices that may not be easy to find.

Yeah doing the polling in each entity is fine.

OK so the calendar entity is a bit special, and so i can explain here how it works. Consider here a scenario for Google calendar: Say every 15 minutes you refresh the cloud calendar, but then a new event shows up. It starts in 5 minutes, so you also need to handle the state transition from "off" to "on". How this works is the calendar base class will handle this for you. You'd just refresh the calendar event every 15 minutes and the base class will set an additional timer based on event for 5 minutes and it will trigger another state change.

See

def async_write_ha_state(self) -> None:
for details on how this works.

So yeah doing it per entity as you said is fine.

@@ -35,6 +61,31 @@ async def async_step_user(
key = slugify(user_input[CONF_CALENDAR_NAME])
self._async_abort_entries_match({CONF_STORAGE_KEY: key})
user_input[CONF_STORAGE_KEY] = key
if url := user_input.get(CONF_CALENDAR_URL):
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Increase test coverage for this file.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure, tests and documentation are a must for the merge. I was coding this from my phone, on my live home assistant instance and I did not have access to tools to run the testsuite.

I will add the tests and a documentation pull request as well

try:
vol.Schema(vol.Url())(url)
except vol.Invalid:
return self.async_show_form(
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Restructure this method to have a single show form call, not one per exception.

self._etag = None
self._update_interval = update_interval

async def _fetch_calendar_and_update(self):
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I imagined this working more like a sync where we fetch the url, writing down to the local filesystem store, but from there the local calendar integration works like normal and is able to serve from the local filesystem store. This means it continues to work offline and truly is still a local calendar. I think it could fetch and write to the store, then work like normal (but still readonly).

I think this could be a good way to think about business logic separation for the "Store" class and fetching/reading/writing. (Right now there is a "store" for a remote calendar entity and it is ambiguous what its for so something needs to be addressed here)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I understand your proposal and I agree with it. It makes a lot of sense. I will implement the changes and tests and ask for a second review.

Thank you very much for your time

@home-assistant home-assistant bot marked this pull request as draft September 28, 2024 16:32
@home-assistant
Copy link

Please take a look at the requested changes, and use the Ready for review button when you are done, thanks 👍

Learn more about our pull request process.

@allenporter
Copy link
Contributor

One thing i wanted to point out is there is another draft PR in parallel adding ability to upload an ICS file. I may take over that PR and try to get it moving as I think adding both of these features for the next release will be a really cool package. We'll just have to figure out how we want the combined config flow to work: Maybe we end up making a radio button with two separate flows for uploading vs importing from a url?

@allenporter
Copy link
Contributor

One thing i wanted to point out is there is another draft PR in parallel adding ability to upload an ICS file. I may take over that PR and try to get it moving as I think adding both of these features for the next release will be a really cool package. We'll just have to figure out how we want the combined config flow to work: Maybe we end up making a radio button with two separate flows for uploading vs importing from a url?

I updated #117955 to support a radio button with option to either (1) create empty or (2) upload the ICS file. We could add (3) to add a new step to import from a URL

@zeehio
Copy link
Contributor Author

zeehio commented Sep 29, 2024

One thing i wanted to point out is there is another draft PR in parallel adding ability to upload an ICS file. I may take over that PR and try to get it moving as I think adding both of these features for the next release will be a really cool package. We'll just have to figure out how we want the combined config flow to work: Maybe we end up making a radio button with two separate flows for uploading vs importing from a url?

I updated #117955 to support a radio button with option to either (1) create empty or (2) upload the ICS file. We could add (3) to add a new step to import from a URL

Great to know. Since it was just merged it's much easier for me to rebase my PR and keep working from there. :-)

@allenporter allenporter added the noteworthy Marks a PR as noteworthy and should be in the release notes (in case it normally would not appear) label Sep 29, 2024
@allenporter
Copy link
Contributor

Talking to one of the other core maintainers, there is a preference to do this in a separate integration "remote calendar". It can copy code from the local calendar component (without the writeable actions) and can share most of the same code (similar to how todo is also using all the same code). Sound reasonable? Let me know if you need any help with this as i think it'll be nice to have this in the next release and i'm happy to do reviews for it/help how i can.

@zeehio
Copy link
Contributor Author

zeehio commented Oct 1, 2024

Talking to one of the other core maintainers, there is a preference to do this in a separate integration "remote calendar". It can copy code from the local calendar component (without the writeable actions) and can share most of the same code (similar to how todo is also using all the same code). Sound reasonable? Let me know if you need any help with this as i think it'll be nice to have this in the next release and i'm happy to do reviews for it/help how i can.

With respect to doing this on a separate integration it makes perfect sense to me as well.

With respect to timings I can't make it to the October release. My free time is limited and not regularly spaced, so I can't commit to having it done by some date, unfortunately.

On the bright side, if you (or anyone else) have the time to push this forward and a clear idea of what needs to get done I will be super happy to step aside and help with code review as much as I can. I am happy as long as eventually we see this feature in.

I will post a message here before I start any kind of further work on this, so please feel free to do the same and take over if you can.

Copy link

There hasn't been any activity on this pull request recently. This pull request has been automatically marked as stale because of that and will be closed if no further activity occurs within 7 days.
If you are the author of this PR, please leave a comment if you want to keep it open. Also, please rebase your PR onto the latest dev branch to ensure that it's up to date with the latest changes.
Thank you for your contribution!

@github-actions github-actions bot added the stale label Nov 30, 2024
@github-actions github-actions bot closed this Dec 7, 2024
@github-actions github-actions bot locked and limited conversation to collaborators Dec 8, 2024
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
cla-signed integration: local_calendar new-feature noteworthy Marks a PR as noteworthy and should be in the release notes (in case it normally would not appear) Quality Scale: No score stale
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants